#ifndef LINEAR_SCHEDULE_H
#define LINEAR_SCHEDULE_H
#include "kern_ll.h"
#include "pthread.h"
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>

// time for scheduler timer
#define SECONDS_SLEEP 0 // rechannelize every 1.5 seconds
#define NANOSECONDS_SLEEP 750000

// identifiers for thread; replicas are copies of tasks
#define THREAD_CONTROL 0
#define THREAD_WORKER 1
#define THREAD_CONTROL_REPLICA 2
#define THREAD_WORKER_REPLICA  3

// type of task
#define REPLICA 0
#define SINGLETON 1

// status for a given thread
#define THREAD_STOPPED 0
#define THREAD_RUNNING 1
#define THREAD_YIELD 2
#define THREAD_WAITING 3

// thread function pointer
typedef int (*PTHREADFN)(void*);


// statistics structure
typedef struct
{
	struct timespec timer;
	u_int64_t running_time;
} STATISTICS, *PSTATISTICS;


// task structure
typedef struct
{
	// should be the domain of the image file
	// total run time will be run_cost+data_size;
	unsigned type : 1;
	unsigned status : 1;
	unsigned int run_cost; // cost for executing
	unsigned int data_cost;
	unsigned int channel;
	unsigned int total_run_cost;
	unsigned int total_data_cost;
	
	void *parent_task;  // pointer to parent task
	
	unsigned int replicated_count; // count of replicated tasks
	
	pthread_t thread; // pthread_ thread
	
	pthread_mutex_t run_lock; // locks the current thread
	unsigned int threadId; // thread identifier (TID)
	
	STATISTICS thread_stats;
	
	PTHREADFN fp; // function pointer
	void *arg; // arguments for new thread
	unsigned short task_at;
	unsigned int sub_task_count; // count for sub tasks
	void *sub_tasks; // sub tasks 
} TASK, *PTASK; // task structure





// priority identifiers for a given task
#define HIGH_MANAGER_TASK_PRIORITY 0
#define HIGH_TASK_PRIORITY 1
#define MIDHIGH_TASK_PRIORITY 2
#define MID_TASK_PRIORITY 3
#define LOWMID_TASK_PRIORITY 4
#define LOW_TASK_PRIORITY 5

typedef struct
{
	// work queue structure identifies
	// a task that is moving between work queues
	PTASK task_ptr;
	LINKEDLIST queue_list;
} WORKQUEUE, *PWORKQUEUE;

 // queue of tasks that need to run, possibly waiting for timer
 // to go off for scheduler
PLINKEDLIST work_queue; 
PLINKEDLIST working_queue; // queue of running tasks

PLINKEDLIST *channels; // list of channels


// POSIX thread variables
pthread_cond_t wait_scheduler;
pthread_cond_t wait_tasks_complete_cond;
pthread_condattr_t wait_attr;
pthread_attr_t highprio; // high priority attribute
pthread_attr_t medprio; // medium priority attribute
pthread_mutex_t wait_mutex;
pthread_mutex_t wait_tasks_mutex;
unsigned int total_task_count;

#define LOW_TO_HIGH 0
#define HIGH_TO_LOW 1

unsigned int sched_id;
unsigned short p_count;
pthread_t scheduler_thread; // thread for channelized scheduler

#define NORMAL_MODE 0
#define STATISTICS_MODE 1

// identifies the scheduler mode
short scheduler_mode;


// initialize the scheduler
void init_scheduler(int comm_arb_id);

// create new parent task
PTASK create_new_task(int sub_task_cnt, PTHREADFN fp, void *arg);
// destroy a given task and sub tasks
void destroy_task(PTASK task);
// creates a worker
void create_worker(PTASK parent_task,PTHREADFN fn,void *arg, unsigned int run_cost, unsigned int data_size);
// runs a given task ( and any sub tasks )
void run_task(PTASK task_to_run);
// scheduler
void linear_sched();
// runs the linear scheduler.
void *run_linear_scheduler(void);
// removes a task from a channel, if it exists
void remove_task(PTASK task, unsigned int channel);
// signal catcher
void catch_sched (int sig);
// task that schedules the scheduler TASK
void sched_scheduler();
// shuts down a task and any sub tasks
u_int64_t shutdown_tasks(PTASK task);
// waits on a task to complete
void wait_task(PTASK task_to_wait);
// returns the task count
unsigned int task_count(PTASK task);

// sets a task to a channel
void set_channel_task(PTASK task,unsigned int channel, unsigned int type);
// sets a task to a channel
void set_channel(unsigned int channel, unsigned int cost_per_channel);

// replicates a task
PTASK replicate_task (PTASK parent_task, PTASK newtask, PTASK sub_task);
// shuts down a task and any sub tasks
void shutdown_parent_task(PTASK task);
// shuts down replicated tasks
u_int64_t shutdown_replicated_tasks_fp(PTHREADFN fp);

// these methods aren't used as much

// gets the working costs within a range
void get_working_costs(unsigned int *min, unsigned int *max);
void get_task_working_cost(PTASK task,unsigned int *min, unsigned int *max);



#define get_tasks_per_channel(void) ((int)(total_task_count))
#endif
